package com.guoxue.action.front;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.guoxue.auth.GXTokenSevice;
import com.guoxue.domain.UserCoinsVo;
import com.guoxue.domain.UserVo;
import com.guoxue.service.IUserCoinsService;
import com.guoxue.service.IUserService;
import com.guoxue.util.ChatUtils;
import com.guoxue.util.HttpUtil;
import com.guoxue.util.LoggerUtil;
import com.guoxue.util.OtherUtils;
import com.guoxue.util.PasswordUtil;
import com.guoxue.util.RedisUtil;
import com.guoxue.util.Sy;
import com.guoxue.util.codeSwitch.khb;
import com.guoxue.util.codeSwitch.zt;

import redis.clients.jedis.Jedis;

@Controller
@RequestMapping("User")
/**
 * 用户登录接口
 * 
 * @author young
 */

public class LoginAction extends BaseAction {

	@Resource
	private IUserService userService;
	@Resource
	private IUserCoinsService coinsService;

	@Resource
	/** 自己的登录token生成和加解密服务对象 */
	private GXTokenSevice gxTokenSevice;

	/**
	 * QQ应用id
	 */
	private static final String qqAppId = "wx3df02eb9204c02ed";

	/**
	 * 创建游戏角色 首先判断是否来自合法访问 其次： 1.当前账号是否存在,这种情况大多数是url盗链，也可能存在session过期等现象
	 * 2.判断当前游戏角色名是否存在
	 * 
	 * @param req
	 * @param resp
	 * @param nickName(必)游戏角色名字
	 * @param account(必)任何一种绑定方式下的账号
	 * @param sex(必)游戏角色性别
	 * @param type(必)登录类型
	 * @param password(必)登录密码
	 * @param code(必)第三方验证token
	 * @return
	 */
	@RequestMapping("/createUserName")
	@ResponseBody
	public JSON A0_loginAndCreateRole(HttpServletRequest req, HttpServletResponse resp, String nickName, String account,
			Integer sex, final Integer type, final String password, final String code) {
		JSON json_rt;

		try {
			khb.ts.tempCodes(); // 新增type,password, code参数;
			final boolean loginSupport = false; // 客户端添加以上几个参数后,将此开关置为true!
			// 1.针对角色创建参数的检查:
			if (isEmpty(nickName) || sex == null) {
				return Message(ERROR, BAD_PARAM, null);
			}
			zt.ta.function(); // 对昵称规则的细化?
			zt.tb.function(); // 对sex取值范围的检查
			if (OtherUtils.isNumber(nickName)) {
				return Message(ERROR, "名称不能为全数字", null);
			}
			if (OtherUtils.getWordCount(nickName) > 20) {
				return Message(ERROR, "昵称过长", null);
			}

			if (loginSupport) {
				// 2.登录参数基本检查, 以及账号密码参数检查(在获取账号Vo前)(根据不同的type):
				json_rt = this.loginOp_step1_withoutVo(account, type, password, code);
				if (json_rt != null) {
					return json_rt; // 非null表示检查未通过,返回值为需要返回给客户端的json对象
				}
			}

			// 3.尝试获取账号Vo,处理账号Vo不存在,或账号角色已创建的情况:
			final UserVo userVo = userService.getUser(account, type);
			if (userVo == null || !isEmpty(userVo.getNickName())) {
				return Message(ERROR, "当前账号存在异常，请重新登录", account);
			}

			if (loginSupport) {
				// 4.数据库中已存在账号Vo数据,针对账号Vo数据完成相关检查:
				json_rt = this.loginOp_step3_withVo(userVo, type, password, code);
				if (json_rt != null) {
					return json_rt; // 非null表示检查未通过,返回值为需要返回给客户端的json对象
				}
			}

			// 4.创建角色,初始化用户数据:
			zt.tb.question(); // 此段操作,需要在同一个数据库事务中进行!
			zt.ta.function(); // 角色信息,不应该放在userVo(实为accountVo)中!
			userVo.setNickName(nickName);
			userVo.setSex(sex);
			userService.saveUser(userVo); // 通过之前绑定账号进行姓名修改
			userVo.setImgUrl(sex == 1 ? "defaultHeadM.png" : "defaultHeadG.png"); // 设置默认头像
			ChatUtils.creatSinglUser(userVo.getId() + "",
					PasswordUtil.MD5Generator(userVo.getId() + "", userVo.getCreatedAt()), nickName);// 添加环信账户
			UserCoinsVo userCoinsVo = new UserCoinsVo();
			userCoinsVo.setUid(userVo.getId());
			userCoinsVo.setSumField(12);
			userCoinsVo.setUsedField(0);
			coinsService.saveUserCoins(userCoinsVo);

			///////////////////////////////////////////////////////////////////////////
			// 执行登录操作:
			// 生成回复数据对象:
			final int uid = userVo.getId();
			final JSONObject json = new JSONObject();// 返回的数据，最终转换为Object
			// 执行登录操作:
			json_rt = this.loginOp_step9_performLogin(req, userVo, uid, json);
			if (json_rt != null) {
				return json_rt; // 处理过程中发生了错误
			}

			// 回复客户端:
			return Message(SUCCESS, "添加昵称成功", json);
		} catch (Exception e) {
			return LoggerUtil.logInfo(e, ERROR);
		}
	}

	/**
	 * 
	 * @param req
	 * @param resp
	 * @param account
	 *            (必)登录账号，快速登录时为手机唯一识别码
	 * @param password
	 *            用户键入密码
	 * @param type
	 *            (必)1:手机号登录。2、QQ登录. 3、微信登录.4、sina登录.5、快速登录.(见CUser.ACCOUNTS_TYPE_系列常数)
	 */
	@RequestMapping(value = "/login")
	@ResponseBody
	public JSON A0_login(HttpServletRequest req, HttpServletResponse resp, final String account, final String password,
			final Integer type, final String code) {
		// String result = "";// 返回处理结果
		// String messageValue = "";// 返回提示消息
		// final Object obj; // 返回数据data
		final UserVo userVo, userVo_new;// 用户账号Vo对象
		String GxToken = "";// 自身系统之间的交互协议
		// final JSONObject json;// 返回的数据，最终转换为Object
		JSON json_rt;

		try {
			// 1.参数基本检查, 以及账号密码参数检查(在获取账号Vo前)(根据不同的type):
			json_rt = this.loginOp_step1_withoutVo(account, type, password, code);
			if (json_rt != null) {
				return json_rt; // 非null表示检查未通过,返回值为需要返回给客户端的json对象
			}

			// 2.尝试获取账号Vo,处理账号Vo不存在的情况:
			userVo = userService.getUser(account, type);// 根据account和accountType,尝试从数据库获取账号Vo对象
			if (userVo == null) { // 数据库中,账号尚未创建
				// 初始化账号Vo对象:
				userVo_new = new UserVo();
				userVo_new.setStatus(1);
				if (type == 2) { // QQ用户
					userVo_new.setQqAccount(account);
				} else if (type == 3) { // 微信用户
					userVo_new.setWechatAccount(account);
				} else if (type == 4) { // sina用户
					userVo_new.setSinaAccount(account);
				} else if (type == 1) {
					return Message(ERROR, "当前账户不存在", null);
				} else if (type == 5) { // 快速登录
					userVo_new.setIdentityId(account);
					userVo_new.setStatus(2); // 设置为游客账号状态
				}
				userVo_new.setCreatedAt(OtherUtils.getCurrentDate());
				// 将账号Vo对象,插入到数据库中:
				userService.saveUser(userVo_new);
				// 通知客户端INFO_NOT_COMPLETE,需要通过createUserName,创建用户角色:
				return Message(INFO_NOT_COMPLETE, "账号信息未完善", null);
			}
			// 3.数据库中已存在账号Vo数据,针对账号Vo数据完成相关检查:
			json_rt = this.loginOp_step3_withVo(userVo, type, password, code);
			if (json_rt != null) {
				return json_rt; // 非null表示检查未通过,返回值为需要返回给客户端的json对象
			}

			//////////////////////////////// 至此,通过了登录检查,执行登录操作:
			// 生成回复数据对象:
			final int uid = userVo.getId();
			final JSONObject json = new JSONObject();// 返回的数据，最终转换为Object
			// 执行登录操作:
			json_rt = this.loginOp_step9_performLogin(req, userVo, uid, json);
			if (json_rt != null) {
				return json_rt; // 处理过程中发生了错误
			}

			// 回复客户端:
			return Message(SUCCESS, "登录成功", json);
		} catch (Exception e) {
			return LoggerUtil.logInfo(e, ERROR);
		}
	}

	/**
	 * 登录处理方法:最后一步,通过了所有登录检查,执行登录操作
	 * 
	 * @param req
	 * @param userVo
	 *            数据库中的账号Vo数据对象
	 * @param uid
	 *            用户id
	 * @param json
	 *            准备回复给客户端的数据对象
	 * @return 非null表示处理过程中发生了错误,需要返回给客户端的json对象。null表示处理成功,未发生错误。
	 * @throws Exception
	 */
	private JSON loginOp_step9_performLogin(final HttpServletRequest req, final UserVo userVo, final int uid,
			final JSONObject json) throws Exception {
		final String gxToken;

		json.put("uid", uid);
		json.put("easemobPass", PasswordUtil.MD5Generator(userVo.getId() + "", userVo.getCreatedAt()));

		// 生成GxToken(需要sessionID、userid、当前时间(ms)):
		final String sessionId = req.getSession(true).getId();
		final long lTime = System.currentTimeMillis();
		gxToken = gxTokenSevice.getToken(sessionId, uid, "" + lTime);
		json.put("GxToken", gxToken);
		// 存储token到session:
		final HttpSession httpSession = req.getSession(true);
		httpSession.setAttribute("GxToken", gxToken);
		// // 将userVo存入session:
		// zt.ta.question(); // 将userVo存入session是否必要?
		// httpSession.setAttribute("user", userVo);

		zt.ta.function(); // 基于Spring管理Redis连接!
		return null; // 没有发生错误
	}

	/**
	 * 登录处理方法:第三步,数据库中已存在账号Vo数据,针对账号Vo数据完成相关检查
	 * 
	 * @param userVo
	 *            数据库中的账号Vo数据对象
	 * @param type
	 *            1:手机号登录。2、QQ登录. 3、微信登录.4、sina微博登录.5、快速登录.(见CUser.ACCOUNTS_TYPE_系列常数)
	 * @param password
	 *            用户键入密码
	 * @param code
	 *            第三方登录验证所需的token,具体含义由type参数决定。
	 * @return 非null表示检查未通过,需要返回给客户端的json对象。null表示通过了检查。
	 * @throws Exception
	 */
	private JSON loginOp_step3_withVo(final UserVo userVo, final Integer type, final String password, final String code)
			throws Exception {
		// 数据库中已存在账号Vo数据,针对账号Vo数据完成相关检查:
		// a.检查账号是否处于封停状态:
		if (userVo.getStatus() != 1 && userVo.getStatus() != 2) {// 帐号是否禁用
			zt.ta.function(); // userVo.status,需要通过标志位(而非数值)来记录不同的用户状态组合!
			zt.ta.function(); // 数据库中,与时间相关的字段,尽量重构为long而非String!
			zt.ta.function(); // 将UserVo改名为AccountVo(包括修改数据库表名)
			zt.ta.function(); // 引入GameTime
			return Message(ERROR, "账号已被封号，请联系客服", null);
		}
		// b.检查账号是否已创建角色。若尚未创建,通知客户端,通过createUserName,创建用户角色:
		if (isEmpty(userVo.getNickName()) || userVo.getSex() <= 0) {// 帐号是否有角色和性别
			// 通知客户端INFO_NOT_COMPLETE,需要通过createUserName,创建用户角色:
			return Message(INFO_NOT_COMPLETE, "账号信息未完善", null);
		}
		// c.基于账号Vo对象,完成最后的登录检查:
		if (type == 1) {// 手机登录
			if (PasswordUtil.validPassword(userVo.getUserPassword(), password, userVo.getSalt())) {// 校验密码
				zt.ta.question(); // 注释掉了将userVo放入session的语句,似乎没有必要?(因为登录成功操作中,会进行此项工作)
				// req.getSession().setAttribute("user", userVo);
			} else {
				return Message(ERROR, PASSWORD_ERROR, null);
			}
		} else if (type == 5) {
		} else {
		}
		return null; // 通过了检查
	}

	/**
	 * 登录处理方法:第一步,完成基本参数检查,以及在获取账号Vo前的账号密码参数检查
	 * 
	 * @param account
	 *            登录账号,具体含义由type参数决定。
	 * @param type
	 *            1:手机号登录。2、QQ登录.
	 *            3、微信登录.4、sina微博登录.5、快速登录.(见CUser.ACCOUNTS_TYPE_系列常数)
	 * @param password
	 *            用户键入密码
	 * @param code
	 *            第三方登录验证所需的token,具体含义由type参数决定。
	 * @return 非null表示检查未通过,需要返回给客户端的json对象。null表示通过了检查。
	 * @throws Exception
	 */
	private JSON loginOp_step1_withoutVo(final String account, final Integer type, final String password,
			final String code) throws Exception {
		JSON json_rt;
		// 参数基本检查:
		if (isEmpty(account)) {
			return Message(ERROR, BAD_PARAM, null);
		}
		if (type == null || type <= 0 || type > 5) {
			return Message(ERROR, "未知登录类型", null);
		}
		// 账号密码参数检查(在获取账号Vo前)(根据不同的type):
		if (type == 1) {// 手机号登录
			if (isEmpty(password)) { // 密码为空
				return Message(ERROR, "账号密码错误", null);
			}
		} else if (type == 5) { // 快速登录
			zt.tb.function(); // 快速登录,对账号字符串"account"的合法性(长度等)进行检查
			// result = SUCCESS;
		} else {
			json_rt = this.loginOp_thirdPartyLoginValidate(type, code, account);
			if (json_rt != null) {
				return json_rt; // 非null表示检查未通过,返回值为需要返回给客户端的json对象
			}
		}
		return null; // 通过了检查
	}

	/**
	 * 第三方登录验证方法
	 * 
	 * @param type
	 *            1:手机号登录。2、QQ登录. 3、微信登录.4、sina微博登录.5、快速登录.(只接受2,3,4)(见CUser.ACCOUNTS_TYPE_系列常数)
	 * @param code
	 *            第三方登录验证所需的token,具体含义由type参数决定。
	 * @param account
	 *            客户端提交的用户登录账号,具体含义由type参数决定。
	 * @param json
	 *            需要返回给客户端的json对象
	 * @param user
	 *            数据库中的用户账号Vo对象
	 * @return 非null表示检查未通过,需要返回给客户端的json对象。null表示通过了检查。
	 * @throws Exception
	 */
	private JSON loginOp_thirdPartyLoginValidate(final Integer type, final String code, final String account)
			throws Exception {
		if (type < 2 || type > 4) {
			Sy.println("参数错误");
		}

		if (type == 2) {// QQ登录
			String respStr = HttpUtil.sendGet("https://graph.qq.com/oauth2.0/me", "access_token=" + code).replace("(",
					"");
			respStr = respStr.replace(")", "");
			respStr = respStr.replace("callback", "");
			respStr = respStr.replace(";", "");
			JSONObject jsonStr = JSON.parseObject(respStr);
			String openId = (String) jsonStr.get("openid");
			if (isEmpty(openId) || !openId.equals(account)) {
				return Message(ERROR, "QQ登录失效，请重新授权登录", null);
			}
		} else if (type == 3) {// 微信登录
			String respStr = HttpUtil.sendGet("https://api.weixin.qq.com/sns/oauth2/refresh_token",
					"appid=" + qqAppId + "&grant_type=REFRESH_TOKEN&refresh_token=" + code);
			JSONObject jsonStr = JSON.parseObject(respStr);
			String openid = (String) jsonStr.get("openid");
			if (isEmpty(openid) || !openid.equals(account)) {
				return Message(ERROR, "微信登录失效，请重新授权登录", null);
			}
		} else if (type == 4) {// 微博登录
			String respStr = HttpUtil.sendGet("https://api.weibo.com/2/account/get_uid.json", "access_token=" + code);
			JSONObject jsonStr = JSON.parseObject(respStr);
			Long openId = (Long) jsonStr.get("uid");
			if (openId == null || openId != Long.parseLong(account)) {
				return Message(ERROR, "新浪登录失效，请重新授权登录", null);
			}
		} else {
			Sy.println("参数错误");
		}
		return null; // 通过了检查
	}

	@RequestMapping("logout")
	@ResponseBody
	public JSON A0_logout(HttpServletRequest req, HttpServletResponse resp, Integer uid) {
		zt.tb.optimize(); // uid参数是多余的
		final HttpSession httpSession = req.getSession();
		if (httpSession != null) {
			httpSession.removeAttribute("GxToken");
		}
		return null;
	}
}
